package org.apache.rocketmq.remoting.protocol.route;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.MixAll;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

/**
 * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
 * @author：陈清风扬，个人微信号：chenqingfengyangjj。
 * @date:2025/1/8
 * @方法描述：该类的对象存储了Broker集群中所有Broker节点的信息
 */
public class BrokerData implements Comparable<BrokerData> {
    //Broker集群的名称
    private String cluster;
    //Broker节点的名称，在RocketMQ中构建的Broker集群，集群中的主节点和从节点名称是一样的
    //区分主节点的标志是每个节点的节点Id
    private String brokerName;
    //存储Broker集群节点Id和地址的映射关系，key是Broker节点的Id，value就是对应的Broker节点的IP地址
    private HashMap<Long, String> brokerAddrs;
    //存储Broker节点所在的区域名称
    private String zoneName;
    //随机数生成器
    private final Random random = new Random();
    //是否启用Acting Master模式，这个模式就是从节点代理主节点模式，后面引入Broker集群了才会为大家实现该功能
    private boolean enableActingMaster = false;

    //构造方法
    public BrokerData() {

    }

    //拷贝构造方法
    public BrokerData(BrokerData brokerData) {
        this.cluster = brokerData.cluster;
        this.brokerName = brokerData.brokerName;
        if (brokerData.brokerAddrs != null) {
            this.brokerAddrs = new HashMap<>(brokerData.brokerAddrs);
        }
        this.zoneName = brokerData.zoneName;
        this.enableActingMaster = brokerData.enableActingMaster;
    }


    public BrokerData(String cluster, String brokerName, HashMap<Long, String> brokerAddrs) {
        this.cluster = cluster;
        this.brokerName = brokerName;
        this.brokerAddrs = brokerAddrs;
    }


    public BrokerData(String cluster, String brokerName, HashMap<Long, String> brokerAddrs, boolean enableActingMaster) {
        this.cluster = cluster;
        this.brokerName = brokerName;
        this.brokerAddrs = brokerAddrs;
        this.enableActingMaster = enableActingMaster;
    }


    public BrokerData(String cluster, String brokerName, HashMap<Long, String> brokerAddrs, boolean enableActingMaster, String zoneName) {
        this.cluster = cluster;
        this.brokerName = brokerName;
        this.brokerAddrs = brokerAddrs;
        this.enableActingMaster = enableActingMaster;
        this.zoneName = zoneName;
    }



    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @date:2025/1/8
     * @方法描述：从Broker集群中选择一个Broker节点地址的方法
     */
    public String selectBrokerAddr() {
        //先从存放Broker各个节点地址的map中获得主节点的地址，主节点的Id是0，所以直接获得对应地址即可
        String masterAddress = this.brokerAddrs.get(MixAll.MASTER_ID);
        //如果没有得到主节点的地址，那么随机选取一个从节点的地址，返回即可
        if (masterAddress == null) {
            List<String> addrs = new ArrayList<>(brokerAddrs.values());
            return addrs.get(random.nextInt(addrs.size()));
        }
        return masterAddress;
    }



    //以下都是简单的get、set方法，我就不添加详细注释了

    public HashMap<Long, String> getBrokerAddrs() {
        return brokerAddrs;
    }


    public void setBrokerAddrs(HashMap<Long, String> brokerAddrs) {
        this.brokerAddrs = brokerAddrs;
    }


    public String getCluster() {
        return cluster;
    }


    public void setCluster(String cluster) {
        this.cluster = cluster;
    }


    public boolean isEnableActingMaster() {
        return enableActingMaster;
    }


    public void setEnableActingMaster(boolean enableActingMaster) {
        this.enableActingMaster = enableActingMaster;
    }


    public String getZoneName() {
        return zoneName;
    }


    public void setZoneName(String zoneName) {
        this.zoneName = zoneName;
    }



    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((brokerAddrs == null) ? 0 : brokerAddrs.hashCode());
        result = prime * result + ((brokerName == null) ? 0 : brokerName.hashCode());
        return result;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        BrokerData other = (BrokerData) obj;
        if (brokerAddrs == null) {
            if (other.brokerAddrs != null) {
                return false;
            }
        } else if (!brokerAddrs.equals(other.brokerAddrs)) {
            return false;
        }
        return StringUtils.equals(brokerName, other.brokerName);
    }


    @Override
    public String toString() {
        return "BrokerData [brokerName=" + brokerName + ", brokerAddrs=" + brokerAddrs + ", enableActingMaster=" + enableActingMaster + "]";
    }


    @Override
    public int compareTo(BrokerData o) {
        return this.brokerName.compareTo(o.getBrokerName());
    }


    public String getBrokerName() {
        return brokerName;
    }


    public void setBrokerName(String brokerName) {
        this.brokerName = brokerName;
    }
}
